;Tested in every area; works and allows game completion but adds artificial difficulty
;Bugs:
; - Opens life force doors in the incorrect order.
;	The code does not associate life force doors with enemy groups.
;	In the first room with 2 life force doors in Vela's first level, the battleship, each door will open once all enemies are killed.
;	It has not been confirmed if the doors opened in the order they usually would, but it probably won't affect the game much.
;	However, at the beginning of Cerulean, killing the enemies in the first area opens the wrong door.
;	Entering that wrong door and leaving causes that door to become locked and the correct door to open, allowing gameplay to continue normally if the door that was opened incorrectly is the next one opened.
;	In general, leaving the area and returning should fix such issues.
;	Cerulean's tunnels are another example - the doors open in the incorrect order, and the player must leave and come back once to finish the area and more times to acquire everything from it.
;	The doors opening in the wrong order means that the area can be completed more easily, which prompts players to miss secrets if they don't put in extra effort (which may be a good thing).
;	Other levels like Eschebone require lots of back and forth to progress.
;	It may be necessary to disable the hack for certain rooms if it becomes an issue.
; - Lingering objects can sometimes cause enemies not to spawn, preventing life force door requirements from being met
;	Sometimes the enemies will randomly appear after objects like guns and heads are collected, allowing the door to be opened
;	These enemies usually spawn on the corpses of other enemies and do not move, making them hard to spot
;This hack (supposedly) causes bodies of the slain to linger
;while allowing life force doors to still open correctly

;	Body Linger
;JAL to this code from 0xB1EE764C and NOP the instruction after it to use the hack
;Code is currently placed at the location defined below which is JAL'd to by 0x0C1FFF00
.equ				BODY_LINGER_OFFSET, 0x007FFC00

;Make code only be moved to new memory location if it isn't there already
.long				0xD6000000 + BODY_LINGER_OFFSET
ADDIU	SP,	SP,	0xFFE8	;First instruction;
				;will copy memory if and only if it's not already there

;From the trainer spec,
;"Writes the following ([count] * 8) bytes to [address] (dword)"
.long				0x85000000 + BODY_LINGER_OFFSET
.long				(BodyLingerEnd - BodyLingerStart)/8

				BodyLingerStart:
;Back up registers
ADDIU	SP,	SP,	0xFFE8	;
SW	S0,	0x0000	(SP)	;
SW	S1,	0x0004	(SP)	;
SW	S2,	0x0008	(SP)	;
SW	S3,	0x000C	(SP)	;
SW	T1,	0x0010	(SP)	;
SW	T2,	0x0014	(SP)	;

;Load byte to check if enemy is dead
LBU	S0,	0x0055	(T0)	;

;Return if they are
ADDIU	S0,	S0,	-0x0001	;
BNEZ	S0,			BodyLingerReturn
;NOP

;Mark enemy as dead
ORI	S1,	R0,	0x0002	;
SB	S1,	0x0055	(T0)	;

;Load pointer to block containing "group pointer" and return if it's null
LW	S0,	0x0024	(T0)	;
BEQZ	S0,			BodyLingerReturn
;NOP

;Load "group pointer" and return if it's null
LW	S1,	0x0068	(S0)	;
BEQZ	S1,			BodyLingerReturn
;NOP

;Load number of enemies remaining in this group and decrement it if it is not 0
LBU	S0,	0x0000	(S1)	;
ADDIU	S2,	S0,	-0x0001	;
BNEZL	S0,			BodyLingerDecrementGroupEnemyCount
SB	S2,	0x0000	(S1)	;
OR	S2,	S0,	R0	;
				BodyLingerDecrementGroupEnemyCount:

;Return if the group is still active
BNEZ	S2,			BodyLingerReturn
;NOP

; Return if the group is not a VIP group
LBU	S0,	0x0075	(S1)	;
BEQZ	S0,			BodyLingerReturn
;NOP

;Acquire the pointer to the data regarding the area's life force door
ORI	S3,	R0,	0x0007	;Flags indicating it's a life force door
ORI	T2,	R0,	0x0028	;Flags indicating the life force door is the active one
LUI	S0,	0x800F		;
LW	S0,	0x2CA4	(S0)	;
BEQZ	S0,			BodyLingerReturn
NOP
				BodyLingerDoorSearchLoop:
LW	S1,	0x0000	(S0)	;
BEQZ	S1,			BodyLingerReturn
NOP
LHU	S2,	0x0048	(S1)	;
BNE	S2,	S3,		BodyLingerDoorSearchLoop
ADDIU	S0,	S0,	0x0004	;
LW	S2,	0x0068	(S1)	;
LHU	T1,	0x003E	(S2)	;
AND	T1,	T1,	T2	;
BNE	T1,	T2,		BodyLingerDoorSearchLoop
;NOP

;Decrement the count of VIP groups remaining if the count is not 0
LBU	S1,	0x004A	(S2)	;
ADDIU	S0,	S1,	-0x0001	;
BNEZL	S1,			BodyLingerDecrementVIPGroupCount
SB	S0,	0x004A	(S2)	;
OR	S0,	S1,	R0	;
				BodyLingerDecrementVIPGroupCount:

;Return if there are still groups active
BNEZ	S0,			BodyLingerReturn
;NOP

;Open the door
ORI	S1,	R0,	0x0030	;
SH	S1,	0x003E	(S2)	;

				BodyLingerReturn:
;Restore registers
LW	S0,	0x0000	(SP)	;
LW	S1,	0x0004	(SP)	;
LW	S2,	0x0008	(SP)	;
LW	S3,	0x000C	(SP)	;
LW	T1,	0x0010	(SP)	;
LW	T2,	0x0014	(SP)	;
JR	RA			;
ADDIU	SP,	SP,	0x0018	;

;Calculate size of this code
.align				3
				BodyLingerEnd:

;End conditional memory copy
.long				0xE0000000
.long				0x00000000
;	End of Body Linger
